package com.smart.community.region.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.regex.Pattern;

/**
 * 数据验证工具类
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 */
@Slf4j
@Component
public class DataValidationUtils {

    // 正则表达式
    private static final Pattern BUILDING_NO_PATTERN = Pattern.compile("^[A-Za-z0-9]{1,20}$");
    private static final Pattern ROOM_NUMBER_PATTERN = Pattern.compile("^[0-9]{1,4}$");
    private static final Pattern HOUSEHOLD_CODE_PATTERN = Pattern.compile("^[A-Za-z0-9-]{1,50}$");
    private static final Pattern UNIT_NO_PATTERN = Pattern.compile("^[0-9]{1,3}$");

    /**
     * 验证楼栋数据
     */
    public ValidationResult validateBuildingData(List<Map<String, Object>> buildings, Long communityId) {
        ValidationResult result = new ValidationResult();
        Set<String> buildingNos = new HashSet<>();
        Set<String> buildingNames = new HashSet<>();
        
        for (int i = 0; i < buildings.size(); i++) {
            Map<String, Object> building = buildings.get(i);
            int rowIndex = i + 2; // Excel行号从2开始（第1行是标题）
            
            // 验证楼栋编号
            String buildingNo = (String) building.get("buildingNo");
            if (!StringUtils.hasText(buildingNo)) {
                result.addError(rowIndex, "楼栋编号", "楼栋编号不能为空");
                continue;
            }
            if (!BUILDING_NO_PATTERN.matcher(buildingNo).matches()) {
                result.addError(rowIndex, "楼栋编号", "楼栋编号格式不正确，只能包含字母、数字，长度1-20位");
            }
            if (!buildingNos.add(buildingNo)) {
                result.addError(rowIndex, "楼栋编号", "楼栋编号重复：" + buildingNo);
            }
            
            // 验证楼栋名称
            String buildingName = (String) building.get("buildingName");
            if (!StringUtils.hasText(buildingName)) {
                result.addError(rowIndex, "楼栋名称", "楼栋名称不能为空");
            } else if (buildingName.length() > 50) {
                result.addError(rowIndex, "楼栋名称", "楼栋名称长度不能超过50个字符");
            } else if (!buildingNames.add(buildingName)) {
                result.addError(rowIndex, "楼栋名称", "楼栋名称重复：" + buildingName);
            }
            
            // 验证楼层数
            Object floorCountObj = building.get("floorCount");
            if (floorCountObj == null) {
                result.addError(rowIndex, "楼层数", "楼层数不能为空");
            } else {
                try {
                    int floorCount = Integer.parseInt(floorCountObj.toString());
                    if (floorCount < 1 || floorCount > 100) {
                        result.addError(rowIndex, "楼层数", "楼层数必须在1-100之间");
                    }
                } catch (NumberFormatException e) {
                    result.addError(rowIndex, "楼层数", "楼层数必须是整数");
                }
            }
            
            // 验证单元数量
            Object unitCountObj = building.get("unitCount");
            if (unitCountObj == null) {
                result.addError(rowIndex, "单元数量", "单元数量不能为空");
            } else {
                try {
                    int unitCount = Integer.parseInt(unitCountObj.toString());
                    if (unitCount < 1 || unitCount > 20) {
                        result.addError(rowIndex, "单元数量", "单元数量必须在1-20之间");
                    }
                } catch (NumberFormatException e) {
                    result.addError(rowIndex, "单元数量", "单元数量必须是整数");
                }
            }
            
            // 验证每层户数
            Object unitsPerFloorObj = building.get("unitsPerFloor");
            if (unitsPerFloorObj == null) {
                result.addError(rowIndex, "每层户数", "每层户数不能为空");
            } else {
                try {
                    int unitsPerFloor = Integer.parseInt(unitsPerFloorObj.toString());
                    if (unitsPerFloor < 1 || unitsPerFloor > 20) {
                        result.addError(rowIndex, "每层户数", "每层户数必须在1-20之间");
                    }
                } catch (NumberFormatException e) {
                    result.addError(rowIndex, "每层户数", "每层户数必须是整数");
                }
            }
            
            // 验证建筑年代
            Object buildYearObj = building.get("buildYear");
            if (buildYearObj != null) {
                try {
                    int buildYear = Integer.parseInt(buildYearObj.toString());
                    int currentYear = Calendar.getInstance().get(Calendar.YEAR);
                    if (buildYear < 1900 || buildYear > currentYear) {
                        result.addError(rowIndex, "建筑年代", "建筑年代必须在1900-" + currentYear + "之间");
                    }
                } catch (NumberFormatException e) {
                    result.addError(rowIndex, "建筑年代", "建筑年代必须是整数");
                }
            }
            
            // 验证楼栋类型
            String buildingType = (String) building.get("buildingType");
            if (StringUtils.hasText(buildingType) && buildingType.length() > 20) {
                result.addError(rowIndex, "楼栋类型", "楼栋类型长度不能超过20个字符");
            }
            
            // 验证备注
            String remark = (String) building.get("remark");
            if (StringUtils.hasText(remark) && remark.length() > 200) {
                result.addError(rowIndex, "备注", "备注长度不能超过200个字符");
            }
        }
        
        return result;
    }

    /**
     * 验证单元数据
     */
    public ValidationResult validateUnitData(List<Map<String, Object>> units, 
                                           List<Map<String, Object>> buildings, 
                                           Long communityId) {
        ValidationResult result = new ValidationResult();
        
        // 构建楼栋映射
        Map<String, Map<String, Object>> buildingMap = new HashMap<>();
        for (Map<String, Object> building : buildings) {
            String buildingNo = (String) building.get("buildingNo");
            buildingMap.put(buildingNo, building);
        }
        
        // 单元唯一性检查
        Set<String> unitKeys = new HashSet<>();
        
        for (int i = 0; i < units.size(); i++) {
            Map<String, Object> unit = units.get(i);
            int rowIndex = i + 2; // Excel行号从2开始（第1行是标题）
            
            // 验证楼栋编号
            String buildingNo = (String) unit.get("buildingNo");
            if (!StringUtils.hasText(buildingNo)) {
                result.addError(rowIndex, "楼栋编号", "楼栋编号不能为空");
                continue;
            }
            
            // 检查楼栋是否存在
            if (!buildingMap.containsKey(buildingNo)) {
                result.addError(rowIndex, "楼栋编号", "楼栋编号不存在：" + buildingNo);
                continue;
            }
            
            // 验证单元编号
            Object unitNoObj = unit.get("unitNo");
            if (unitNoObj == null) {
                result.addError(rowIndex, "单元编号", "单元编号不能为空");
                continue;
            }
            
            String unitNoStr = unitNoObj.toString();
            if (!UNIT_NO_PATTERN.matcher(unitNoStr).matches()) {
                result.addError(rowIndex, "单元编号", "单元编号格式不正确，必须是1-3位数字");
                continue;
            }
            
            int unitNo = Integer.parseInt(unitNoStr);
            
            // 检查单元唯一性
            String unitKey = buildingNo + "-" + unitNo;
            if (!unitKeys.add(unitKey)) {
                result.addError(rowIndex, "单元编号", "单元编号重复：" + buildingNo + "-" + unitNo);
            }
            
            // 验证单元名称
            String unitName = (String) unit.get("unitName");
            if (!StringUtils.hasText(unitName)) {
                result.addError(rowIndex, "单元名称", "单元名称不能为空");
            } else if (unitName.length() > 50) {
                result.addError(rowIndex, "单元名称", "单元名称长度不能超过50个字符");
            }
            
            // 验证楼层数
            Object floorCountObj = unit.get("floorCount");
            if (floorCountObj == null) {
                result.addError(rowIndex, "楼层数", "楼层数不能为空");
            } else {
                try {
                    int floorCount = Integer.parseInt(floorCountObj.toString());
                    if (floorCount < 1 || floorCount > 100) {
                        result.addError(rowIndex, "楼层数", "楼层数必须在1-100之间");
                    }
                    
                    // 检查楼层数是否与楼栋楼层数一致
                    Map<String, Object> building = buildingMap.get(buildingNo);
                    if (building != null) {
                        Object buildingFloorCountObj = building.get("floorCount");
                        if (buildingFloorCountObj != null) {
                            int buildingFloorCount = Integer.parseInt(buildingFloorCountObj.toString());
                            if (floorCount != buildingFloorCount) {
                                result.addError(rowIndex, "楼层数", "单元楼层数(" + floorCount + ")与楼栋楼层数(" + buildingFloorCount + ")不一致");
                            }
                        }
                    }
                } catch (NumberFormatException e) {
                    result.addError(rowIndex, "楼层数", "楼层数必须是整数");
                }
            }
            
            // 验证房间数量
            Object roomCountObj = unit.get("roomCount");
            if (roomCountObj == null) {
                result.addError(rowIndex, "房间数量", "房间数量不能为空");
            } else {
                try {
                    int roomCount = Integer.parseInt(roomCountObj.toString());
                    if (roomCount < 1 || roomCount > 1000) {
                        result.addError(rowIndex, "房间数量", "房间数量必须在1-1000之间");
                    }
                } catch (NumberFormatException e) {
                    result.addError(rowIndex, "房间数量", "房间数量必须是整数");
                }
            }
            
            // 验证户数
            Object householdCountObj = unit.get("householdCount");
            if (householdCountObj != null) {
                try {
                    int householdCount = Integer.parseInt(householdCountObj.toString());
                    if (householdCount < 0) {
                        result.addError(rowIndex, "户数", "户数不能为负数");
                    }
                } catch (NumberFormatException e) {
                    result.addError(rowIndex, "户数", "户数必须是整数");
                }
            }
            
            // 验证电梯数量
            Object elevatorCountObj = unit.get("elevatorCount");
            if (elevatorCountObj != null) {
                try {
                    int elevatorCount = Integer.parseInt(elevatorCountObj.toString());
                    if (elevatorCount < 0 || elevatorCount > 10) {
                        result.addError(rowIndex, "电梯数量", "电梯数量必须在0-10之间");
                    }
                } catch (NumberFormatException e) {
                    result.addError(rowIndex, "电梯数量", "电梯数量必须是整数");
                }
            }
            
            // 验证门禁类型
            String doorAccessType = (String) unit.get("doorAccessType");
            if (StringUtils.hasText(doorAccessType)) {
                Set<String> validTypes = new HashSet<>(Arrays.asList("密码", "刷卡", "人脸", "指纹", "混合"));
                if (!validTypes.contains(doorAccessType)) {
                    result.addError(rowIndex, "门禁类型", "门禁类型必须是：密码、刷卡、人脸、指纹、混合");
                }
            }
            
            // 验证状态
            String status = (String) unit.get("status");
            if (StringUtils.hasText(status)) {
                Set<String> validStatuses = new HashSet<>(Arrays.asList("启用", "禁用", "维护"));
                if (!validStatuses.contains(status)) {
                    result.addError(rowIndex, "状态", "状态必须是：启用、禁用、维护");
                }
            }
            
            // 验证备注
            String remark = (String) unit.get("remark");
            if (StringUtils.hasText(remark) && remark.length() > 200) {
                result.addError(rowIndex, "备注", "备注长度不能超过200个字符");
            }
        }
        
        return result;
    }

    /**
     * 验证房户数据
     */
    public ValidationResult validateHouseholdData(List<Map<String, Object>> households,
                                                List<Map<String, Object>> buildings,
                                                List<Map<String, Object>> units,
                                                Long communityId) {
        ValidationResult result = new ValidationResult();
        
        // 构建楼栋映射
        Map<String, Map<String, Object>> buildingMap = new HashMap<>();
        for (Map<String, Object> building : buildings) {
            String buildingNo = (String) building.get("buildingNo");
            buildingMap.put(buildingNo, building);
        }
        
        // 构建单元映射
        Map<String, Map<String, Object>> unitMap = new HashMap<>();
        for (Map<String, Object> unit : units) {
            String buildingNo = (String) unit.get("buildingNo");
            Integer unitNo = (Integer) unit.get("unitNo");
            unitMap.put(buildingNo + "-" + unitNo, unit);
        }
        
        // 房户唯一性检查
        Set<String> householdCodes = new HashSet<>();
        Set<String> roomKeys = new HashSet<>();
        
        for (int i = 0; i < households.size(); i++) {
            Map<String, Object> household = households.get(i);
            int rowIndex = i + 2; // Excel行号从2开始（第1行是标题）
            
            // 验证楼栋编号
            String buildingNo = (String) household.get("buildingNo");
            if (!StringUtils.hasText(buildingNo)) {
                result.addError(rowIndex, "楼栋编号", "楼栋编号不能为空");
                continue;
            }
            
            // 检查楼栋是否存在
            if (!buildingMap.containsKey(buildingNo)) {
                result.addError(rowIndex, "楼栋编号", "楼栋编号不存在：" + buildingNo);
                continue;
            }
            
            // 验证单元编号
            Object unitNoObj = household.get("unitNo");
            if (unitNoObj == null) {
                result.addError(rowIndex, "单元编号", "单元编号不能为空");
                continue;
            }
            
            String unitNoStr = unitNoObj.toString();
            if (!UNIT_NO_PATTERN.matcher(unitNoStr).matches()) {
                result.addError(rowIndex, "单元编号", "单元编号格式不正确，必须是1-3位数字");
                continue;
            }
            
            int unitNo = Integer.parseInt(unitNoStr);
            
            // 检查单元是否存在
            String unitKey = buildingNo + "-" + unitNo;
            if (!unitMap.containsKey(unitKey)) {
                result.addError(rowIndex, "单元编号", "单元编号不存在：" + buildingNo + "-" + unitNo);
                continue;
            }
            
            // 验证房户编号
            String householdCode = (String) household.get("householdCode");
            if (!StringUtils.hasText(householdCode)) {
                result.addError(rowIndex, "房户编号", "房户编号不能为空");
            } else if (!HOUSEHOLD_CODE_PATTERN.matcher(householdCode).matches()) {
                result.addError(rowIndex, "房户编号", "房户编号格式不正确，只能包含字母、数字、连字符，长度1-50位");
            } else if (!householdCodes.add(householdCode)) {
                result.addError(rowIndex, "房户编号", "房户编号重复：" + householdCode);
            }
            
            // 验证房间号
            String roomNumber = (String) household.get("roomNumber");
            if (!StringUtils.hasText(roomNumber)) {
                result.addError(rowIndex, "房间号", "房间号不能为空");
            } else if (!ROOM_NUMBER_PATTERN.matcher(roomNumber).matches()) {
                result.addError(rowIndex, "房间号", "房间号格式不正确，必须是1-4位数字");
            } else {
                // 检查房间号唯一性
                String roomKey = buildingNo + "-" + unitNo + "-" + roomNumber;
                if (!roomKeys.add(roomKey)) {
                    result.addError(rowIndex, "房间号", "房间号重复：" + buildingNo + "-" + unitNo + "-" + roomNumber);
                }
            }
            
            // 验证楼层号
            Object floorNumberObj = household.get("floorNumber");
            if (floorNumberObj == null) {
                result.addError(rowIndex, "楼层号", "楼层号不能为空");
            } else {
                try {
                    int floorNumber = Integer.parseInt(floorNumberObj.toString());
                    if (floorNumber < 1 || floorNumber > 100) {
                        result.addError(rowIndex, "楼层号", "楼层号必须在1-100之间");
                    }
                    
                    // 检查楼层号是否在楼栋楼层范围内
                    Map<String, Object> building = buildingMap.get(buildingNo);
                    if (building != null) {
                        Object buildingFloorCountObj = building.get("floorCount");
                        if (buildingFloorCountObj != null) {
                            int buildingFloorCount = Integer.parseInt(buildingFloorCountObj.toString());
                            if (floorNumber > buildingFloorCount) {
                                result.addError(rowIndex, "楼层号", "楼层号(" + floorNumber + ")超出楼栋楼层数(" + buildingFloorCount + ")");
                            }
                        }
                    }
                } catch (NumberFormatException e) {
                    result.addError(rowIndex, "楼层号", "楼层号必须是整数");
                }
            }
            
            // 验证面积
            Object areaObj = household.get("area");
            if (areaObj == null) {
                result.addError(rowIndex, "面积", "面积不能为空");
            } else {
                try {
                    double area = Double.parseDouble(areaObj.toString());
                    if (area <= 0 || area > 1000) {
                        result.addError(rowIndex, "面积", "面积必须在0-1000平方米之间");
                    }
                } catch (NumberFormatException e) {
                    result.addError(rowIndex, "面积", "面积必须是数字");
                }
            }
            
            // 验证户型
            String houseType = (String) household.get("houseType");
            if (StringUtils.hasText(houseType) && houseType.length() > 20) {
                result.addError(rowIndex, "户型", "户型长度不能超过20个字符");
            }
            
            // 验证朝向
            String orientation = (String) household.get("orientation");
            if (StringUtils.hasText(orientation)) {
                Set<String> validOrientations = new HashSet<>(Arrays.asList("东", "南", "西", "北", "东南", "西南", "东北", "西北", "南北"));
                if (!validOrientations.contains(orientation)) {
                    result.addError(rowIndex, "朝向", "朝向必须是：东、南、西、北、东南、西南、东北、西北、南北");
                }
            }
            
            // 验证装修状态
            String decorationStatus = (String) household.get("decorationStatus");
            if (StringUtils.hasText(decorationStatus)) {
                Set<String> validStatuses = new HashSet<>(Arrays.asList("毛坯", "简装", "精装", "豪装"));
                if (!validStatuses.contains(decorationStatus)) {
                    result.addError(rowIndex, "装修状态", "装修状态必须是：毛坯、简装、精装、豪装");
                }
            }
            
            // 验证房屋类型
            String houseCategory = (String) household.get("houseCategory");
            if (StringUtils.hasText(houseCategory)) {
                Set<String> validCategories = new HashSet<>(Arrays.asList("住宅", "商铺", "办公", "车库", "储藏室"));
                if (!validCategories.contains(houseCategory)) {
                    result.addError(rowIndex, "房屋类型", "房屋类型必须是：住宅、商铺、办公、车库、储藏室");
                }
            }
            
            // 验证状态
            String status = (String) household.get("status");
            if (StringUtils.hasText(status)) {
                Set<String> validStatuses = new HashSet<>(Arrays.asList("空置", "已售", "已租", "自住", "装修中"));
                if (!validStatuses.contains(status)) {
                    result.addError(rowIndex, "状态", "状态必须是：空置、已售、已租、自住、装修中");
                }
            }
            
            // 验证备注
            String remark = (String) household.get("remark");
            if (StringUtils.hasText(remark) && remark.length() > 200) {
                result.addError(rowIndex, "备注", "备注长度不能超过200个字符");
            }
        }
        
        return result;
    }

    /**
     * 验证结果类
     */
    public static class ValidationResult {
        private final List<ValidationError> errors = new ArrayList<>();
        private final List<ValidationWarning> warnings = new ArrayList<>();

        public void addError(int rowIndex, String field, String message) {
            errors.add(new ValidationError(rowIndex, field, message));
        }

        public void addWarning(int rowIndex, String field, String message) {
            warnings.add(new ValidationWarning(rowIndex, field, message));
        }

        public boolean hasErrors() {
            return !errors.isEmpty();
        }

        public boolean hasWarnings() {
            return !warnings.isEmpty();
        }

        public List<ValidationError> getErrors() {
            return errors;
        }

        public List<ValidationWarning> getWarnings() {
            return warnings;
        }

        public int getErrorCount() {
            return errors.size();
        }

        public int getWarningCount() {
            return warnings.size();
        }

        public Map<String, List<ValidationError>> getErrorsByField() {
            Map<String, List<ValidationError>> errorsByField = new HashMap<>();
            for (ValidationError error : errors) {
                errorsByField.computeIfAbsent(error.getField(), k -> new ArrayList<>()).add(error);
            }
            return errorsByField;
        }
    }

    /**
     * 验证错误类
     */
    public static class ValidationError {
        private final int rowIndex;
        private final String field;
        private final String message;

        public ValidationError(int rowIndex, String field, String message) {
            this.rowIndex = rowIndex;
            this.field = field;
            this.message = message;
        }

        public int getRowIndex() {
            return rowIndex;
        }

        public String getField() {
            return field;
        }

        public String getMessage() {
            return message;
        }

        @Override
        public String toString() {
            return String.format("第%d行 %s: %s", rowIndex, field, message);
        }
    }

    /**
     * 验证警告类
     */
    public static class ValidationWarning {
        private final int rowIndex;
        private final String field;
        private final String message;

        public ValidationWarning(int rowIndex, String field, String message) {
            this.rowIndex = rowIndex;
            this.field = field;
            this.message = message;
        }

        public int getRowIndex() {
            return rowIndex;
        }

        public String getField() {
            return field;
        }

        public String getMessage() {
            return message;
        }

        @Override
        public String toString() {
            return String.format("第%d行 %s: %s", rowIndex, field, message);
        }
    }
}
